// Copyright 2019 The rhyme_lph Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
// W [author] rhyme_lph
// u [email]  rhymelph@gmail.com
// y [github] https://github.com/rhymelph

import 'dart:async';

import 'package:base_plugin/base_plugin.dart';
import 'package:finance_app/generated/l10n.dart';
import 'package:finance_app/src/common/config.dart';
import 'package:finance_app/src/entities/account_entity.dart';
import 'package:finance_app/src/entities/business_contact_entity.dart';
import 'package:finance_app/src/entities/currency_rate_entity.dart';
import 'package:finance_app/src/entities/debit_note_detail_entity.dart';
import 'package:finance_app/src/entities/fixed_asset_entity.dart';
import 'package:finance_app/src/entities/grant_entity.dart';
import 'package:finance_app/src/entities/invoice_entity.dart';
import 'package:finance_app/src/entities/ocr_attachment_entity.dart';
import 'package:finance_app/src/entities/payment_detail_entity.dart';
import 'package:finance_app/src/entities/payment_entity.dart';
import 'package:finance_app/src/entities/setting_data_entity.dart';
import 'package:finance_app/src/entities/tax_submission_detail_entity.dart';
import 'package:finance_app/src/http_service/http_common_service.dart';
import 'package:finance_app/src/http_service/http_payment_service.dart';
import 'package:finance_app/src/http_service/http_report_service.dart';
import 'package:finance_app/src/mixin/check_plan_mixin.dart';
import 'package:finance_app/src/mixin/from_attach_mixin.dart';
import 'package:finance_app/src/mixin/init_edit_data_mixin.dart';
import 'package:finance_app/src/page/all_reports/date_report_page.dart';
import 'package:finance_app/src/provider/all_reports/bank_reconciliation/bank_reconciliation_provider.dart';
import 'package:finance_app/src/provider/all_reports/bank_reconciliation/reconcile_account_detail_provider.dart';
import 'package:finance_app/src/provider/all_reports/bank_reconciliation/reconcile_account_record_detail_provider.dart';
import 'package:finance_app/src/provider/all_reports/bank_reconciliation/views/reconcile_account_provider.dart';
import 'package:finance_app/src/provider/dashboard/bank/cash_and_bank_provider.dart';
import 'package:finance_app/src/provider/dashboard/bill/see_payment_provider.dart';
import 'package:finance_app/src/provider/dashboard/contact/business_contact_detail_provider.dart';
import 'package:finance_app/src/provider/dashboard/sales/sales_provider.dart';
import 'package:finance_app/src/provider/dashboard/sales/views/sales_summary_provider.dart';
import 'package:finance_app/src/provider/dashboard/transaction/all_transactions_provider.dart';
import 'package:finance_app/src/router_gen/router_gen_providers.dart';
import 'package:finance_app/src/utils/cash_utils.dart';
import 'package:finance_app/src/utils/date_time_utils.dart';
import 'package:finance_app/src/utils/form_utils.dart';
import 'package:finance_app/src/widgets/bottom_sheet/calendar_bottom_sheet.dart';
import 'package:finance_app/src/widgets/bottom_sheet/currency_bottom_sheet.dart';
import 'package:finance_app/src/widgets/bottom_sheet/default_bottom_sheet.dart';
import 'package:finance_app/src/widgets/bottom_sheet/delete_info_bottom_sheet.dart';
import 'package:finance_app/src/widgets/bottom_sheet/got_it_info_bottom_sheet.dart';
import 'package:finance_app/src/widgets/bottom_sheet/got_it_tip_bottom_sheet.dart';
import 'package:finance_app/src/widgets/bottom_sheet/list_select_bottom_sheet.dart';
import 'package:flutter/material.dart';

class NewCashInProvider extends BaseProvider<PaymentDetailEntity>
    with InitEditDataMixin, CheckPlanMixin, FormAttachMixin {
  bool isRecordPayment = false;

  TextEditingController priceController = TextEditingController();
  FocusNode priceFocusNode = FocusNode();

  TextEditingController otherPriceController = TextEditingController();
  FocusNode otherPriceFocusNode = FocusNode();

  TextEditingController notesController = TextEditingController();
  FocusNode notesFocusNode = FocusNode();

  TextEditingController cashInNumberController = TextEditingController();
  FocusNode cashInNumberFocusNode = FocusNode();

  bool isSelectMode;

  SettingDataCategory transactionPurpose;

  BusinessContactEntity receiver;

  List<InvoiceEntity> invoiceNumbers;

  DateTime date;

  SettingDataPaymentType transactionMethod;

  AccountEntity bankAccount;

  SettingDataTax gstRate;

  bool isCheckInclusive = true;

  TextEditingController chequeTransactionNumberController =
      TextEditingController();
  FocusNode chequeTransactionNumberFocusNode = FocusNode();

  SettingDataCurrency unit;

  List<String> menuList = [
    'Edit',
    'Delete',
  ];

  bool get isShowGrant => transactionPurpose?.key == 'government_grant';

  bool get isShowInvoice => transactionPurpose?.key == 'invoice';

  bool get isShowGst => transactionPurpose?.key == 'gst';

  bool get isShowDebitNote => transactionPurpose?.key == 'debit_note';

  List<String> hideFormList = [];
  List<String> unableFromList = [];
  List<String> addToList = [];

  String orderType;

  GrantEntity grant;

  TaxSubmissionDetailEntity taxPeriod;
  List<TaxSubmissionDetailEntity> taxList;
  DebitNoteDetailEntity debitNoteNumber;

  int assetId;
  String assetNumber;
  String assetName;

  @override
  void dispose() {
    super.dispose();
    chequeTransactionNumberController.dispose();
    chequeTransactionNumberFocusNode.dispose();
    priceController.dispose();
    priceFocusNode.dispose();
    notesController.dispose();
    notesFocusNode.dispose();
    cashInNumberController.dispose();
    cashInNumberFocusNode.dispose();
  }

  @override
  void initState() {
    super.initState();
  }

  void initHideFromAndUnable() {
    hideFormList.clear();
    unableFromList.clear();
    switch (this.orderType) {
      case 'invoice':
      case 'bill':
        hideFormList.add(S.current.transaction_purpose);
        if (receiver != null) {
          unableFromList.add(S.current.received_from);
        }
        if (invoiceNumbers != null && invoiceNumbers.length > 1) {
          unableFromList.add(S.current.price);
        }
        break;
      case 'gst':
        if (priceController.text.isNotEmpty) {
          unableFromList.add(S.current.price);
        }
        unableFromList.add(S.current.received_from);
        if (transactionPurpose != null) {
          unableFromList.add(S.current.transaction_purpose);
        }
        if (taxPeriod != null) {
          unableFromList.add(S.current.tax_period);
        }
        break;
      case 'bank':
        if (bankAccount != null) {
          unableFromList.add(S.current.bank_account);
        }
        break;
      case 'debit_note':
        hideFormList.add(S.current.transaction_purpose);
        if (receiver != null) {
          unableFromList.add(S.current.received_from);
        }
        if (priceController.text.isNotEmpty) {
          unableFromList.add(S.current.price);
        }
        if (debitNoteNumber != null) {
          unableFromList.add(S.current.debit_note_number);
        }
        break;
      case 'fa_disposal':
        unableFromList.add(S.current.transaction_purpose);
        break;
      default:
        addToList.add(S.current.gst_rate);
        break;
    }
  }

  void unFocus() {
    priceFocusNode.unfocus();
    chequeTransactionNumberFocusNode.unfocus();
    otherPriceFocusNode.unfocus();
    cashInNumberFocusNode.unfocus();
  }

  void onChangeDebitNoteNumber() {}

  void onSave() async {
    FocusManager.instance.primaryFocus.unfocus();
    if (isShowInvoice) {
      if (receiver == null) {
        showToast(S.current.please_select_received_from);
        return;
      }

      if (invoiceNumbers == null || invoiceNumbers.length == 0) {
        showToast(S.current.please_select_invoice_number);
        return;
      }
    }

    if (cashInNumberController.text.length == 0) {
      showToast(S.current.please_enter_transaction_number);
      return;
    }

    if (bankAccount == null) {
      showToast(S.current.please_select_bank_account);
      return;
    }
    if (transactionMethod == null) {
      showToast(S.current.please_select_payment_method);
      return;
    }
    if (priceController.text.length == 0) {
      showToast(S.current.please_enter_price_number);
      return;
    }

    if (isShowDebitNote && debitNoteNumber == null) {
      showToast(S.current.please_select_debit_note_number);
      return;
    }

    if (transactionPurpose.key == 'fa_disposal') {
      obtainContext?.call((context) {
        showRecordFixedAssetSalesInfoBottomSheet(context, onGotIt: () async {
          Navigator.pop(context);
          FixedAssetEntity result = await Routes.navigateTo(
              RouterGenProviders.salesOfFixedAssetPage,
              params: {
                'assetName': assetName,
                'id': assetId,
                'salesDate': date.toIso8601String(),
                'salesPrice': priceController?.text,
                'unit': unit
              });

          if (result != null) {
            assetNumber = result.refNumber;
            assetId = result.id;
            onSaveAPI();
          }
        });
      });
      return;
    }
    onSaveAPI();
  }

  void onSaveAPI() async {
    PaymentEntity orderEntity;
    List<String> numbers = [];
    List<int> numberIds = [];
    if (isShowInvoice) {
      numbers = invoiceNumbers.map((e) => e.number).toList();
      numberIds = invoiceNumbers.map((e) => e.id).toList();
    } else if (isShowGrant) {
      numberIds = [grant.id];
    } else if (isShowDebitNote) {
      numbers.add(debitNoteNumber.number);
      numberIds.add(debitNoteNumber.id);
    } else if (isShowGst) {
      numberIds.add(taxPeriod.id);
    } else if (orderType == 'fa_disposal' ||
        transactionPurpose?.key == 'fa_disposal') {
      numbers.add(assetNumber);
      numberIds.add(assetId);
    }

    List<int> attachmentIds = await uploadFiles();
    if (attachmentIds == null) return;

    if (isEdit == true) {
      await post(
          HttpPaymentService.paymentUpdateCashIn(
            data.id,
            contact_id: receiver?.id,
            number: cashInNumberController.text,
            type: transactionPurpose?.key == 'fa_disposal'
                ? 'fa_sold'
                : transactionPurpose?.key,
            account_id: bankAccount?.id,
            payment_type_id: transactionMethod?.id,
            tax_id: gstRate?.id,
            is_tax_inclusive: isCheckInclusive ? 1 : 0,
            tax_amount: getGSTInfo(),
            issued_at: DateTimeUtils.formatDateTime(date, 'yyyy-MM-dd'),
            currency_code: unit.key,
            total: priceController?.text,
            cheque_number: chequeTransactionNumberController?.text,
            numbers: numbers,
            number_ids: numberIds,
            account_total: unit?.key != bankAccount?.currencyCode
                ? otherPriceController.text
                : null,
            notes: notesController?.text,
            attachment_ids: attachmentIds,
          ),
          loadingTip: 'Loading',
          autoHandler: AutoHandler.Dialog, onSuccess: (result) {
        orderEntity = getEntityFromResult<PaymentEntity>(result);
      });
    } else {
      await post(
          HttpPaymentService.paymentCashIn(
            contact_id: receiver?.id,
            number: cashInNumberController.text,
            type: transactionPurpose?.key,
            account_id: bankAccount?.id,
            payment_type_id: transactionMethod?.id,
            tax_id: gstRate?.id,
            is_tax_inclusive: isCheckInclusive ? 1 : 0,
            tax_amount: getGSTInfo(),
            issued_at: DateTimeUtils.formatDateTime(date, 'yyyy-MM-dd'),
            currency_code: unit?.key,
            total: priceController?.text,
            cheque_number: chequeTransactionNumberController?.text,
            numbers: numbers,
            number_ids: numberIds,
            account_total: unit?.key != bankAccount?.currencyCode
                ? otherPriceController.text
                : null,
            notes: notesController?.text,
            attachment_ids: attachmentIds,
          ),
          loadingTip: 'Loading',
          autoHandler: AutoHandler.Dialog, onSuccess: (result) {
        orderEntity = getEntityFromResult<PaymentEntity>(result);
      });
    }
    if (orderEntity != null) {
      refreshHomeDashboard();

      Providers.get<CashAndBankProvider>(
              RouterGenProviders.cashAndBankPage, null)
          ?.onRefresh();
      if (orderType == 'invoice') {
        Providers.get<SalesProvider>(RouterGenProviders.salesPage, null)
            ?.getChildProvider<SalesSummaryProvider>()
            ?.onRefresh();
      }
      if (isShowGst) {
        Providers.get<DateReportProvider>(
                RouterGenProviders.dateReportPage, null)
            ?.onRequestRefresh();
      }
      if (orderType == 'bank') {
        Providers.get<ReconcileAccountDetailProvider>(
                RouterGenProviders.reconcileAccountDetailPage, null)
            ?.onRequestRefresh();
        Providers.get<ReconcileAccountRecordDetailProvider>(
                RouterGenProviders.reconcileAccountRecordDetailPage, null)
            ?.onRequestRefresh();
      }

      Providers.get<AllTransactionsProvider>(
              RouterGenProviders.allTransactionsPage, null)
          ?.onRequestRefresh();

      if (isSelectMode == true) {
        obtainContext?.call((context) {
          Navigator.of(context).pop(orderEntity);
        });
      } else {
        id = orderEntity.id;
        await post(editDataFuture,
            loadingTip: S.current.loading,
            autoHandler: AutoHandler.Toast, onSuccess: (result) async {
          isEdit = false;
          data = await transformData(
              getEntityFromResult<PaymentDetailEntity>(result), false);
          update();
        });
      }
    }
  }

  void refreshHomeDashboard() {
    Config.dashboardProvider
        .onRefreshDashboard(refreshTransaction: false, refreshOverview: false);
  }

  void onChangeTransactionPurpose() {
    unFocus();
    // obtainContext?.call((context) async {
    //   transactionPurpose =
    //       await showTransactionPurposeBottomSheet(context, transactionPurpose);
    //   update();
    // });
    obtainContext?.call((context) async {
      final result = await Routes.navigateTo(
          RouterGenProviders.selectTransactionPurposePage,
          params: {
            'select': transactionPurpose,
            'isCashOut': false,
          });
      if (result != null) {
        transactionPurpose = result;
        if (isShowGst) {
          _loadTaxSubmissions();
        } else {
          taxPeriod = null;
        }
        print('key:${transactionPurpose.key}');
        update();
      }
      // transactionPurpose =
      //     await showTransactionPurposeBottomSheet(context, transactionPurpose);
    });
  }

  void onChangeReceiver() {
    unFocus();
    obtainContext?.call((context) async {
      receiver = await Routes.navigateTo(
          RouterGenProviders.businessContactsPage,
          params: {
            'select': receiver,
          });
      update();
    });
  }

  void onChangeInvoiceNumber() {
    if (receiver == null) {
      showToast(S.current.please_select_receiver_from);
      return;
    }
    obtainContext?.call((context) async {
      final result = await Routes.navigateTo(
          RouterGenProviders.invoiceNumberPage,
          params: {
            'selects': invoiceNumbers,
            'isMultiple': true,
            'filterIssueTo': receiver.id,
          });
      if (result != null) {
        invoiceNumbers = result;
        num total = 0;
        invoiceNumbers.forEach((element) {
          try {
            total += (element.unpaid ?? 0);
          } catch (e) {
            print(e);
          }
        });
        priceController.text = CashUtils.formatCashAmount2(total);
      }
      if (invoiceNumbers != null && invoiceNumbers.length > 1) {
        unableFromList.add(S.current.price);
      }
      update();
    });
  }

  void onChangeTransactionDate() {
    unFocus();
    obtainContext?.call((context) async {
      date = await showCalendarBottomSheet(context, date);
      update();
    });
  }

  void onChangeTransactionMethod() {
    unFocus();
    obtainContext?.call((context) async {
      transactionMethod =
          await showPaymentMethodBottomSheet(context, transactionMethod);
      update();
    });
  }

  void onChangeBankAccount() {
    unFocus();
    obtainContext?.call((context) async {
      bankAccount =
          await Routes.navigateTo(RouterGenProviders.bankAccountPage, params: {
        'select': bankAccount,
      });
      if (bankAccount != null && bankAccount.currencyCode != unit.key) {
        await post(
            HttpCommonService.currentRate(unit.key, bankAccount.currencyCode,
                DateTimeUtils.formatDateTime(date, 'yyyy-MM-dd')),
            autoHandler: AutoHandler.Toast,
            loadingTip: S.current.loading, onSuccess: (result) {
          final fromRate = getEntityFromResult<CurrencyRateEntity>(result);
          otherPriceController.text = CashUtils.formatCashAmount2(num.parse(
                priceController.text,
              ) *
              fromRate.rate);
        });
      }
      update();
    });
  }

  void onChangeUnit() {
    unFocus();
    obtainContext?.call((context) async {
      unit = await showCurrencyBottomSheet(context, unit);
      update();
    });
  }

  @override
  Future get editDataFuture => HttpPaymentService.showPayment(id);

  void onSelectMenu(String value) {
    switch (value) {
      case 'Edit':
        onChangeEditMode();
        break;
      case 'Delete':
        onDelete();
        break;
    }
  }

  void initBusinessContactDetail() {
    final pro = Providers.get<BusinessContactDetailProvider>(
        RouterGenProviders.businessContactDetailPage, null);
    if (pro != null) {
      this.receiver = pro.contact;
    }
  }

  @override
  FutureOr<PaymentDetailEntity> transformData(
      PaymentDetailEntity d, bool isCache) async {
    id = d.id;
    unit = Config.settingData.currency.firstWhere(
        (element) => element.key == d.currencyCode,
        orElse: () => null);
    cashInNumberController.text = d.number;

    bankAccount = d.account;
    receiver = d.contact;
    gstRate = d.tax;
    isCheckInclusive = d.isTaxInclusive == 1;

    if (d.paymentTypeId != null) {
      transactionMethod = Config.settingData.paymentType.firstWhere(
          (element) => element.id == d.paymentTypeId,
          orElse: () => null);
    }
    if (d.accountTotal != null) {
      otherPriceController.text = CashUtils.formatCashAmount2(d.accountTotal);
    }
    date = DateTimeUtils.toDateTime(d.issuedAt);
    chequeTransactionNumberController.text = d.chequeNumber;
    priceController.text = CashUtils.formatCashAmount2(d.total);
    notesController.text = d.notes;
    FormUtils.toUpperCaseFirst(d.type);

    transactionPurpose =
        Config.cashInCategory.firstWhere((element) => element.key == d.type,
            orElse: () => SettingDataCategory()
              ..name = FormUtils.toUpperCaseFirst(d.type)
              ..key = d.type);
    unit = Config.settingData.currency.firstWhere(
        (element) => d.currencyCode == element.key,
        orElse: () => null);
    if (isShowGrant) {
      if (d.numberIds != null && d.numberIds.length > 0) {
        grant = Config.settingData.grants.firstWhere(
            (element) => element.id == d.numberIds.first,
            orElse: () => null);
      }
    } else if (isShowInvoice) {
      invoiceNumbers = [];
      if (d.numberIds != null && d.numberIds.length > 0) {
        // for (int i = 0; i <= d.numberIds.length; i++) {
        invoiceNumbers.add(InvoiceEntity()
          ..id = d.numberIds[0]
          ..number = d.numbers[0].toString()
          ..total = d.total);
        // }
      }
    } else if (isShowDebitNote) {
      if (d.numbers.length > 0) {
        debitNoteNumber = DebitNoteDetailEntity()
          ..id = d.numberIds.first
          ..number = d.numbers.first.toString();
      }
    } else if (isShowGst) {
      if (taxList == null) await _loadTaxSubmissions(isShowLoading: false);
      if (d.numberIds != null && d.numberIds.length > 0) {
        final id = d.numberIds.first;
        taxPeriod = taxList.firstWhere((element) => element.id == id,
            orElse: () => null);
      }
    }
    orderType = transactionPurpose?.key;
    initHideFromAndUnable();
    handleDataUpdate(d);
    if (isRecordPayment || isShowInvoice) {
      menuList.remove('Edit');
    }
    return super.transformData(d, isCache);
  }

  void onDelete() {
    if (isPlanExpired()) return;
    obtainContext?.call((context) async {
      bool isSuccess = await showDeleteTransactionInfoBottomSheet(context);
      if (isSuccess == true) {
        isSuccess = false;
        await post(HttpPaymentService.deletePayment(data.id),
            loadingTip: S.current.loading,
            autoHandler: AutoHandler.Toast, onSuccess: (result) {
          isSuccess = true;
        });
        if (isSuccess == true) {
          await showDeleteSuccessTipBottomSheet(context);
          Navigator.of(context).pop({
            'delete': true,
          });
          refreshHomeDashboard();
        }
      }
    });
  }

  void initInvoice(
      List<InvoiceEntity> invoiceList,
      BusinessContactEntity receiveFrom,
      num total,
      SettingDataCurrency currency) {
    if (invoiceList != null) {
      isRecordPayment = true;
      transactionPurpose = Config.cashInCategory
          .firstWhere((element) => element.key == 'invoice',
              orElse: () => SettingDataCategory()
                ..name = 'Invoice'
                ..key = 'invoice');
      orderType = 'invoice';
      this.invoiceNumbers = [];
      if (invoiceList.length > 0) {
        invoiceNumbers.addAll(invoiceList);
        this.receiver = invoiceList.first.contact;
        date = DateTimeUtils.toDateTime(invoiceList.first.issuedAt);
      }
    }

    final seePro = Providers.get<SeePaymentProvider>(
        RouterGenProviders.seePaymentPage, null);
    if (seePro != null) {
      isRecordPayment = true;
    }
    if (receiveFrom != null) {
      this.receiver = receiveFrom;
    }
    if (total != null) {
      num _total = total;
      if (_total < 0) {
        _total = -total;
      }
      priceController.text = CashUtils.formatCashAmount2(_total);
    }
    if (currency != null) {
      this.unit = currency;
    }
  }

  @override
  String get type => 'money_in';

  @override
  TextEditingController get numberCtl => cashInNumberController;

  void onChangeGrant() async {
    final result =
        await Routes.navigateTo(RouterGenProviders.selectGrantPage, params: {
      'select': grant,
    });
    if (result != null) {
      grant = result;
      update();
    }
  }

  void initType(String type) {
    if (orderType == null) {
      orderType = type;
    }
    if (type == 'gst') {
      transactionPurpose =
          Config.cashInCategory.firstWhere((element) => element.key == type,
              orElse: () => SettingDataCategory()
                ..key = type
                ..name = FormUtils.toUpperCaseFirst(type));
      unit = Config.settingData.currency
          .firstWhere((element) => element.key == 'SGD');
      date = DateTime.tryParse(taxPeriod.endDate).add(Duration(days: 1));
    }
  }

  bool addition(String s) {
    return addToList.contains(s);
  }

  void onChangeTaxPeriod() {
    obtainContext?.call((context) async {
      TaxSubmissionDetailEntity _select;

      await showDefaultBottomSheet(
        context,
        child: ListSelectBottomSheet<TaxSubmissionDetailEntity>(
          currentSelect: taxPeriod,
          onSelectValue: (data) {
            _select = data;
          },
          group: taxList,
          buildDisplayName: (__) =>
              '${DateTimeUtils.formatDateTimeString(__.startDate)} - ${DateTimeUtils.formatDateTimeString(__.endDate)}',
        ),
        title: S.current.tax_period,
        isScrollControlled: true,
      );
      if (_select != null) {
        taxPeriod = _select;
        update();
      }
    });
  }

  Future<void> _loadTaxSubmissions({bool isShowLoading = true}) async {
    await post(HttpReportService.taxSubmissions(),
        autoHandler: AutoHandler.Toast,
        loadingTip: isShowLoading ? S.current.loading : null,
        onSuccess: (result) {
      taxList = getEntityFromResult<List<TaxSubmissionDetailEntity>>(result);
      if (isShowLoading) {
        taxPeriod = taxList.first;
      }
      update();
    });
  }

  void initDetailDate(PaymentDetailEntity detailData) async {
    if (detailData == null) return;
    data = await transformData(detailData, false);
  }

  void initBankReconciliation() {
    final bankReconciliation = Providers.get<BankReconciliationProvider>(
            RouterGenProviders.bankReconciliationPage, null)
        ?.getChildProvider<ReconcileAccountProvider>();
    if (bankReconciliation != null) {
      this.orderType = 'bank';
      this.bankAccount = bankReconciliation.currentAccount;
      num difference;
      difference = Providers.get<ReconcileAccountRecordDetailProvider>(
              RouterGenProviders.reconcileAccountRecordDetailPage, null)
          ?.difference;
      if (difference == null) {
        difference = Providers.get<ReconcileAccountDetailProvider>(
                RouterGenProviders.reconcileAccountDetailPage, null)
            ?.difference;
      }
      if (difference < 0) {
        difference = -difference;
      }
      this.priceController.text = CashUtils.formatCashAmount2(difference);
      this.unit = Config.settingData.currency.firstWhere(
          (element) => element.key == this.bankAccount.currencyCode,
          orElse: () => null);
    }
  }

  void initCashBank() {
    final cashBankPro = Providers.get<CashAndBankProvider>(
        RouterGenProviders.cashAndBankPage, null);
    if (cashBankPro != null) {
      this.bankAccount = cashBankPro.currentAccount;
    }
  }

  void initDebitNote(DebitNoteDetailEntity debitNote) {
    if (debitNote == null) return;
    debitNoteNumber = debitNote;
    priceController.text = CashUtils.formatCashAmount2(debitNote.unpaid);
    transactionPurpose = Config.cashOutCategory
        .firstWhere((element) => element.key == 'debit_note',
            orElse: () => (SettingDataCategory()
              ..key = 'debit_note'
              ..name = 'Debit Note'));
    orderType = 'debit_note';
    date = DateTime.tryParse(debitNote.issuedAt);
    receiver = debitNote.contact;
    unit = Config.settingData.currency.firstWhere(
        (element) => element.key == debitNote.currencyCode,
        orElse: () => null);
  }

  void initSalesOfFixedAsset(
      int assetId, String assetNumber, String assetName) {
    if (assetId == null || assetName == null) return;
    orderType = 'fa_disposal';
    this.assetId = assetId;
    this.assetNumber = assetNumber;
    this.assetName = assetName;
  }

  void onSelectGstRate() {
    unFocus();
    obtainContext?.call((context) async {
      gstRate = await showGstRateBottomSheet(context, gstRate);
      update();
    });
  }

  void onChangeInclusive() {
    unFocus();
    isCheckInclusive = !isCheckInclusive;
    update();
  }

  double getGSTInfo() {
    double amount = double.parse(priceController.text, (e) => 0.0);
    if (gstRate == null) return 0;

    double rateDouble = gstRate.rate / 100;
    if (isCheckInclusive == true) {
      double sourceAmount = amount / (1 + rateDouble);
      double inclusive = amount - sourceAmount;
      return inclusive.toDouble();
    } else {
      double gst = amount * rateDouble;
      return gst.toDouble();
    }
  }

  @override
  // TODO: implement attachments
  List<OcrAttachmentEntity> get attachments => data?.attachments;
}
